package com.youxin.busfoundation.common;

import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;

public class UidGenerator
{
    final static char[] digits = {
            '0', '1', '2', '3', '4', '5',
            '6', '7', '8', '9', 'a', 'b',
            'c', 'd', 'e', 'f', 'g', 'h',
            'i', 'j', 'k', 'l', 'm', 'n',
            'o', 'p', 'q', 'r', 's', 't',
            'u', 'v', 'w', 'x', 'y', 'z',
            'A', 'B', 'C', 'D', 'E', 'F',
            'G', 'H', 'I', 'J', 'K', 'L',
            'M', 'N', 'O', 'P', 'Q', 'R',
            'S', 'T', 'U', 'V', 'W', 'X',
            'Y', 'Z', '-', '_',
    };

    final static List<Character> digitsList = new ArrayList<Character>();
    static {
        for (int j = 0; j < digits.length; j++) {
            digitsList.add(digits[j]);
        }
    }

    /**
     * 十进制BigInteger转16进制String
     * @param n
     * @return
     */
    public static String encode_b64(BigInteger n){
        char[] table = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_".toCharArray();
        List<Character> result = new ArrayList<Character>();
        BigInteger tmp = n;
        BigInteger zero = new BigInteger("0");
        BigInteger b64 = new BigInteger("64");
        if (tmp.equals(0)){
            result.add('0');
        }else {
            while (tmp.compareTo(zero) == 1){
                BigInteger[] res =  tmp.divideAndRemainder(b64);
                BigInteger index = res[1];
                result.add(table[index.intValue()]);
                tmp = res[0];
            }
        }
        Collections.reverse(result);
        StringBuilder str = new StringBuilder();
        for (Character character : result) {// 对ArrayList进行遍历，将字符放入StringBuilder中
            str.append(character);
        }
        //        return Collections.reverse(ttt);
        return str.toString();
    }

    /**
     * 16进制字符串转10进制BigInteger
     * @param str
     * @return
     */
    public static BigInteger decode_b64(String str){
        BigInteger result = new BigInteger("0");
        for(char c : str.toCharArray()){
            result = result.multiply(new BigInteger("64"));
            int index = digitsList.indexOf(c);
            result = result.add(new BigInteger(String.valueOf(index)));
        }
        return result;
    }



    /**
     * 把10进制的数字转换成64进制
     *
     * @param number
     * @param shift
     * @return
     */
    public static String compressNumber(long number, int shift) {
        char[] buf = new char[64];
        int charPos = 64;
        int radix = 1 << shift;
        long mask = radix - 1;
        do {
            buf[--charPos] = digits[(int) (number & mask)];
            number >>>= shift;
        } while (number != 0);
        return new String(buf, charPos, (64 - charPos));
    }

    /**
     * 把10进制的数字转换成64进制
     *
     * @param number
     * @return
     */
    public static String compressNumber(long number) {
        return compressNumber(number, 6);
    }

    /**
     * 把64进制的字符串转换成10进制
     *
     * @param decompStr
     * @return
     */
    public static long unCompressNumber(String decompStr) {
        long result = 0;
        for (int i = decompStr.length() - 1; i >= 0; i--) {
            if (i == decompStr.length() - 1) {
                result += getCharIndexNum(decompStr.charAt(i));
                continue;
            }
            for (int j = 0; j < digits.length; j++) {
                if (decompStr.charAt(i) == digits[j]) {
                    result += ((long) j) << 6 * (decompStr.length() - 1 - i);
                }
            }
        }
        return result;
    }

    /**
     * @param ch
     * @return
     */
    private static long getCharIndexNum(char ch) {
        int num = ((int) ch);
        if (num >= 48 && num <= 57) {
            return num - 48;
        } else if (num >= 97 && num <= 122) {
            return num - 87;
        } else if (num >= 65 && num <= 90) {
            return num - 29;
        } else if (num == 43) {
            return 62;
        } else if (num == 47) {
            return 63;
        }
        return 0;
    }


    public static String decodeUnicode(final String dataStr) {
        int start = 0;
        int end = 0;
        final StringBuffer buffer = new StringBuffer();
        while (start > -1) {
            end = dataStr.indexOf("\\u", start + 2);
            String charStr = "";
            if (end == -1) {
                charStr = dataStr.substring(start + 2, dataStr.length());
            } else {
                charStr = dataStr.substring(start + 2, end);
            }
            char letter = (char) Integer.parseInt(charStr, 16); // 16进制parse整形字符串。
            buffer.append(new Character(letter).toString());
            start = end;
        }
        return buffer.toString();
    }

    public static String gbEncoding(final String gbString)
    {
        char[] utfBytes = gbString.toCharArray();
        String unicodeBytes = "";
        for (int byteIndex = 0; byteIndex < utfBytes.length; byteIndex++) {
            String hexB = Integer.toHexString(utfBytes[byteIndex]);
            if (hexB.length() <= 2) {
                hexB = "00" + hexB;
            }
            unicodeBytes = unicodeBytes + "\\u" + hexB;
        }
        //        System.out.println("unicodeBytes is: " + unicodeBytes);
        return unicodeBytes;
    }

    public static String getUid(String raw)
    {
        byte[] company_name = fullHalfChange(raw);
        MessageDigest md5 = null;
        try
        {
            md5 = MessageDigest.getInstance("MD5");
        } catch (NoSuchAlgorithmException e)
        {
            e.printStackTrace();
        }
        md5.update(company_name);
        byte[] md = md5.digest();
        long v = byteToLong(md);
        String uid =encode_b64(new BigInteger(asUnsignedDecimalString(v)));

        return uid;
    }

    private static byte[] fullHalfChange(String line)
    {
        char[] charArray = line.toCharArray();
        String rstring = "";
        for (char c : charArray)
        {
            String ucode = gbEncoding(String.valueOf(c));
            String num16 = ucode.replace("\\u", "");
            int int10 = Integer.parseInt(num16, 16);
            if (int10 == 12288)
            {
                int10 = 32;
            } else if (int10 >= 65281 && int10 <= 65374)
            {
                int10 -= 65248;
            }
            rstring += decodeUnicode("\\u" + Integer.toHexString(int10));
        }

        byte[] rsByte = new byte[0];
        try
        {
            rsByte = rstring.getBytes("utf-8");
        } catch (UnsupportedEncodingException e)
        {
            e.printStackTrace();
        }

        return rsByte;
    }

    /**
     * byte[] 轉換成 long
     * @param b
     * @return
     */
    public static long byteToLong(byte[] b) {
        long s = 0;
        long s0 = b[0] & 0xff;// 最低位
        long s1 = b[1] & 0xff;
        long s2 = b[2] & 0xff;
        long s3 = b[3] & 0xff;
        long s4 = b[4] & 0xff;// 最低位
        long s5 = b[5] & 0xff;
        long s6 = b[6] & 0xff;
        long s7 = b[7] & 0xff; // s0不变
        s1 <<= 8;
        s2 <<= 16;
        s3 <<= 24;
        s4 <<= 8 * 4;
        s5 <<= 8 * 5;
        s6 <<= 8 * 6;
        s7 <<= 8 * 7;
        s = s0 | s1 | s2 | s3 | s4 | s5 | s6 | s7;
        return s;
    }

    private static final BigInteger TWO_64 = BigInteger.ONE.shiftLeft(64);

    /**
     * long 轉換成無符號的long
     * @param l
     * @return
     */
    public static  String asUnsignedDecimalString(long l) {
        BigInteger b = BigInteger.valueOf(l);
        if(b.signum() < 0) {
            b = b.add(TWO_64);
        }
        return b.toString();
    }


    /**
     * 获取时间字符串
     * @param timeStr
     * @return
     */
    public static String getTimeStampStr(String timeStr){
        String res;
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date date = null;
        try {
            date = simpleDateFormat.parse(timeStr);
            long ts = date.getTime();
            res = String.valueOf(ts);
            res = res.substring(0, res.length()-3);
            return res;
        } catch (ParseException e) {
            e.printStackTrace();
            return "";
        }

    }
}
